/*
 * Copyright 2016-2036 the original author or authors.
 * 
 * COMMERCIAL USE OF THIS SOFTWARE WITHOUT WARRANTY IS NOT ALLOWED.
 * Use is subject to license terms! You can distribute a copy of this software
 * to others for free. This software is a non-profit and open-source project.
 * Any contribution to this project will make it better.
 * All rights reserved! Owned by Stephen Liu.
 * 
 */
package com.github.hingo.config;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author ste7en.liu@gmail.com
 * @since 2016/10/21
 */
@Configuration
@MapperScan(
    basePackages = "com.github.hingo.persistence",
    sqlSessionTemplateRef = "sqlSessionTemplate"
)
public class ServiceConfig {

    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Value("classpath:mybatis-config.xml")
    private Resource configLocation;
    @Value("classpath:com/github/hingo/mapper/*.xml")
    private Resource[] mapperLocations;

    @Bean(name = "dataSource", destroyMethod = "close")
    public DruidDataSource dataSource() throws SQLException {

        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setMaxActive(40);
        dataSource.setInitialSize(5);
        dataSource.setMaxWait(30000);
        dataSource.setMinIdle(1);
        dataSource.setTimeBetweenEvictionRunsMillis(3000);
        dataSource.setMinEvictableIdleTimeMillis(300000);
        dataSource.setValidationQuery("select 1");
        dataSource.setTestWhileIdle(true);
        dataSource.setTestOnBorrow(false);
        dataSource.setTestOnReturn(false);
        dataSource.setPoolPreparedStatements(true);
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
        dataSource.setFilters("config");
        Properties properties = new Properties();
        properties.put("config.decrypt", "true");
        dataSource.setConnectProperties(properties);
        StatFilter statFilter = new StatFilter();
        statFilter.setSlowSqlMillis(5000);
        statFilter.setMergeSql(true);

        List<Filter> filterList = new ArrayList<>();
        filterList.add(statFilter);
        dataSource.setProxyFilters(filterList);
        return dataSource;
    }


    /**
     * 配置SqlSessionFactory，可以自动把{@link DruidDataSource}注入进来
     * @return SqlSessionFactory对象
     */
    @Bean(autowire = Autowire.BY_NAME)
    public SqlSessionFactoryBean sqlSessionFactory() {
        SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
        sqlSessionFactory.setConfigLocation(configLocation);
        sqlSessionFactory.setMapperLocations(mapperLocations);
        return sqlSessionFactory;
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory().getObject());
    }

    @Bean(name = "transactionManager")
    public DataSourceTransactionManager txManager() throws SQLException {
        DataSourceTransactionManager txManager = new DataSourceTransactionManager();
        txManager.setDataSource(dataSource());
        return txManager;
    }
}
